﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;

namespace Solidi
{
	/// <remarks>
	/// Thread-safe
	/// </remarks>
	sealed class RootCircularDependencyResolver : IDependencyResolver
	{
		private LinkedList<CircularDependency> _stack = new LinkedList<CircularDependency>();
		private IDependencyResolver _resolver;

		public RootCircularDependencyResolver(IDependencyResolver resolver)
		{
			_resolver = resolver;
		}

		public bool TryResolve(object graphId, IDependencyContainer container, IDependencyKey key, out object instance)
		{
			lock (_stack)
			{
				foreach (CircularDependency parent in _stack)
				{
					if (parent.IsCircular(key))
					{
						if (parent.TryAcquirePrevious(graphId, container, out instance))
						{
							return true;
						}
						else
						{
                            throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "Circular dependency in graph for key {0}.", key), "key");
						}
					}
				}

				_stack.AddFirst(new CircularDependency(key));

				try
				{
					return _resolver.TryResolve(graphId, container, key, out instance);
				}
				finally
				{
					_stack.RemoveFirst();
				}
			}
		}

		public bool TryResolve(IDependencyContainer container, IDependencyKey key, out object instance)
		{
			return _resolver.TryResolve(container, key, out instance);
		}

		public bool TryRelease(IDependencyContainer container, object instance)
		{
			return _resolver.TryRelease(container, instance);
		}
	}
}
